using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using Constants = PHSRAG.Insight21.InsightUtilities.Constants;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;

namespace PHSRAG.Insight21.Agreements
{
    public class PatientCareDetails : BusinessObjects.BusinessObject
    {
        #region Constants
        /// <summary>
        /// Get the key to be used in all caching operations for this instance of the object.
        /// </summary>
        public const string CacheKey = "PatientCareDetails_80744F77-3A53-4d29-A8DA-FB6BF05374B4";
        public const string RecordCountKey = "RecordCount_80744F77-3A53-4d29-A8DA-FB6BF05374B4";
        public const string AmountSumKey = "AmountSum_80744F77-3A53-4d29-A8DA-FB6BF05374B4";
        public const string DiscountSumKey = "DiscountSum_80744F77-3A53-4d29-A8DA-FB6BF05374B4";
        public const string ExtendedSumKey = "ExtendedSum_80744F77-3A53-4d29-A8DA-FB6BF05374B4";
        #endregion

        #region Private Fields
        private int recordCount;
        private decimal amountSum;
        private decimal discountSum;
        private decimal extendedSum;
        #endregion

        #region Enumerations (Private)
        // Enumerates the arguments required for loadingExpense details.
        private enum LoadMethodArgs
        {
            SearchCriteria,
            FundNumber,
            SortColumn,
            SortAscending,
            PageNumber,
            RowsToFetch,
            Count
        }

        private enum DataTables
        {
            Details,
            Agregates
        }

        public enum PatientCareDetailColumn
        {
            Id,
            FundMRN,
            PatientName,
            PatientMRN,
            PostDate,
            ServiceDate,
            ChargeCode,
            CPTCode,
            ChargeDescription,
            Quantity,
            Amount,
            Discount,
            ExtendedAmount
        }

        private enum AgregateColumns
        {
            RecordCount,
            AmountSum,
            DiscountSum,
            ExtendedSum
        }
        #endregion

        public PatientCareDetails(ICachePolicy cachePolicy)
            : base(cachePolicy)
        {
        }

        #region Public Properties
        private const string GetPatientCareDetailsSPROCName = "GetPatientCareDetails";
        public int RecordCount { get { return recordCount; } }
        public decimal AmountSum { get { return amountSum; } }
        public decimal DiscountSum { get { return discountSum; } }
        public decimal ExtendedSum { get { return extendedSum; } }
        #endregion

        public void Reset()
        {
            DataContainer = null;
            recordCount = 0;
            amountSum = 0;
            discountSum = 0;
            extendedSum = 0;
            CachePolicy.UnCache(RecordCountKey);
            CachePolicy.UnCache(AmountSumKey);
            CachePolicy.UnCache(DiscountSumKey);
            CachePolicy.UnCache(ExtendedSumKey);
        }

        #region BusinessObject Methods
        /// <summary>
        /// Cache the current instance using the prevalent cache policy.
        /// </summary>
        public override void Cache()
        {
            CachePolicy.Cache(CacheKey, this);
        }
        /// <summary>
        /// Remove the current instance from the cache using the prevalent cache policy.
        /// </summary>
        public override void UnCache()
        {
            CachePolicy.UnCache(CacheKey);
        }

        /// <summary>
        /// Load the current instance with Patient Care details data for the current user.
        /// </summary>
        /// <param name="connectionString">Database connection string</param>
        /// <param name="args">Is expected to contain the SearchCriteria instance
        public override void Load(string connectionString, params object[] args)
        {
            if (!args.Length.Equals((int)LoadMethodArgs.Count))
                throw new ArgumentException(String.Format("Patient Care Details requires {0} parameters",
                    LoadMethodArgs.Count));

            try
            {
                // We persist the overall recordcount so we don't select count() in each pass of
                // the db.  Reset() needs to be called when the criteria changes.
                object o = CachePolicy.GetCachedObject(RecordCountKey);
                recordCount = (o == null) ? 0 : (int)o;

                SearchCriteria searchCriteria = (SearchCriteria)args[(int)LoadMethodArgs.SearchCriteria];

                SqlParameter[] sqlParams = DataAccess.BuildSqlParameterArray(
                    "@fundNumber", SqlDbType.VarChar, args[(int)LoadMethodArgs.FundNumber].ToString()
                    , "@patientMRN", SqlDbType.VarChar, searchCriteria[Constants.PatientMRNKey]
                    , "@patientFirstName", SqlDbType.VarChar, searchCriteria[Constants.FirstNameKey]
                    , "@patientLastName", SqlDbType.VarChar, searchCriteria[Constants.LastNameKey]
                    , "@chargeCode", SqlDbType.Int, searchCriteria[Constants.ChargeCodeKey]
                    , "@fundMRN", SqlDbType.VarChar, searchCriteria[Constants.InstitutionalMRNKey]
                    , "@postFromDate", SqlDbType.DateTime, searchCriteria[Constants.PostFromDateKey]
                    , "@postToDate", SqlDbType.DateTime, searchCriteria[Constants.PostToDateKey]
                    , "@serviceFromDate", SqlDbType.DateTime, searchCriteria[Constants.ServiceFromDateKey]
                    , "@serviceToDate", SqlDbType.DateTime, searchCriteria[Constants.ServiceToDateKey]
                    , "@daily", SqlDbType.Bit, searchCriteria["daily"]
                    , "@sortColumn", SqlDbType.VarChar, args[(int)LoadMethodArgs.SortColumn].ToString()
                    , "@sortAscending", SqlDbType.Bit, (bool)args[(int)LoadMethodArgs.SortAscending]
                    , "@pageNumber", SqlDbType.Int, (int)args[(int)LoadMethodArgs.PageNumber]
                    , "@rowsToFetch", SqlDbType.Int, (int)args[(int)LoadMethodArgs.RowsToFetch]
                    , "@totalRowCount", SqlDbType.Int, recordCount);

				DataContainer = DataAccess.GetDataSet(connectionString, GetPatientCareDetailsSPROCName,
                                sqlParams);
                SaveAgregates();
            }
			catch(Exception ex)
			{
				throw new Utility.InsightException(@"Error in loading Patient Care Details", ex);
			}
        }
        #endregion

        private void SaveAgregates()
        {
            if (DataContainer.Tables.Count > 1)
            {
                DataTable table = DataContainer.Tables[(int)DataTables.Agregates];

                recordCount = (int)table.Rows[0][(int)AgregateColumns.RecordCount];
                CachePolicy.Cache(RecordCountKey, recordCount);

                if (recordCount > 0)
                {
                    amountSum = (decimal)table.Rows[0][(int)AgregateColumns.AmountSum];
                    CachePolicy.Cache(AmountSumKey, amountSum);

                    discountSum = (decimal)table.Rows[0][(int)AgregateColumns.DiscountSum];
                    CachePolicy.Cache(DiscountSumKey, discountSum);

                    extendedSum = (decimal)table.Rows[0][(int)AgregateColumns.ExtendedSum];
                    CachePolicy.Cache(ExtendedSumKey, extendedSum);
                }
            }
        }
    }
}
